package com.yoyo.itravel.service.impl;

import com.yoyo.itravel.bean.SightOrder;
import com.yoyo.itravel.bean.SightTicketStock;
import com.yoyo.itravel.bean.TicketTypeDetail;
import com.yoyo.itravel.constants.DateFormatConstant;
import com.yoyo.itravel.constants.OrderConstant;
import com.yoyo.itravel.dao.ISightOrderDao;
import com.yoyo.itravel.dao.ISightTicketStockDao;
import com.yoyo.itravel.dao.ITicketTypeDetailDao;
import com.yoyo.itravel.exceptions.SightOrderException;
import com.yoyo.itravel.service.ISightOrderService;
import com.yoyo.itravel.utils.DateUtils;
import com.yoyo.itravel.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.sql.SQLException;
import java.util.*;

/**
 * @Description 景点门票订单服务层接口的实现类
 * @Author HZX
 * @Version 1.0
 * @Date 2020/6/26 12:42
 */
@Service
public class SightOrderServiceImpl implements ISightOrderService {

    @Autowired
    private ISightOrderDao sightOrderDao;
    @Autowired
    private ITicketTypeDetailDao ticketTypeDetailDao;
    @Autowired
    private ISightTicketStockDao sightTicketStockDao;

    /**
     * @Description 创建景点门票订单
     *
     * @Param sightOrder
     * @Return boolean
     */
    @Override
    public boolean createSightOrder(SightOrder sightOrder) throws SightOrderException {
        try {
            if (sightOrder == null) {
                return false;
            }

            /** 具体门票库存数量减一，这里需要同步 **/
            synchronized (SightOrderServiceImpl.class) {
                // 通过景点门票详细类型和出行日期获得SightTicketStock存对象
                List<SightTicketStock> sightTicketStocks = sightTicketStockDao.selectByCondition(new SightTicketStock(DateUtils.parseDate(sightOrder.getTripDate(),
                        DateFormatConstant.DATE_FORMAT_YYYY_MM_DD), sightOrder.getDetailTypeId()));
                // TODO
                SightTicketStock sightTicketStock = null;
                if (sightTicketStocks.size() != 1) {
                    return false;
                }
                sightTicketStock = sightTicketStocks.get(0);
                // 通过sightStock对象获得当天景点门票数量
                Integer nowStockNum = sightTicketStock.getNowStockNum();
                if (nowStockNum == 0) {
                    // 库存为0，直接返回
                    return false;
                }

                // 库存数量减一
                sightTicketStockDao.updateById(new SightTicketStock(sightTicketStock.getTicketStockId(), nowStockNum - sightOrder.getOrderNum()));
                // 生成订单
                if (sightOrderDao.insert(sightOrder) == 1) {
                    // 开启定时器，当订单超时未支付，则自动修改订单状态为已取消，并将库存数回滚
                    orderTimeoutCancel(sightOrder.getOrderId(), sightTicketStock.getTicketStockId(), nowStockNum);
                }
                // 返回
                return true;
            }

        } catch (SQLException e) {
            e.printStackTrace();
            throw new SightOrderException("创建景点门票订单失败...");
        }
    }

    /**
     * @Description 定时器时间到后修改订单状态为待点评
     *
     * @Param sightOrder
     * @Return boolean
     */
    @Override
    public boolean preCommentTimer(SightOrder sightOrder) throws SightOrderException {
        if (sightOrder == null) {
            return false;
        }
        // 开启定时器
        orderCommentStatus(sightOrder);
        return true;
    }


    /**
     * @Description 通过订单号修改订单状态
     *
     * @Param orderId
     * @Param orderStatus
     * @Return boolean
     */
    @Override
    public boolean updateOrderStatus(String orderId, Integer orderStatus) throws SightOrderException {
        if (StringUtils.isEmpty(orderId) || orderStatus == null) {
            return false;
        }

        try {
            // TODO 支付后回调sightOrderDao为null【待解决】
            return sightOrderDao.updateOrderStatus(orderId, orderStatus) == 1;
        } catch (SQLException e) {
            e.printStackTrace();
            throw new SightOrderException("通过订单号修改订单状态失败...");
        }
    }

    /**
     * @param out_trade_no
     * @param trade_no
     * @return boolean
     * @Description 添加订单交易号
     */
    @Override
    public boolean addTradeNoByOrderId(String out_trade_no, String trade_no) throws SightOrderException {
        if (StringUtils.isEmpty(out_trade_no, trade_no)) {
            return false;
        }
        try {
            return sightOrderDao.addTradeNoByOrderId(out_trade_no, trade_no) == 1;
        } catch (SQLException e) {
            e.printStackTrace();
            throw new SightOrderException("添加订单交易号失败...");
        }
    }

    /**
     * @return java.util.List<cn.hut.travel.bean.SightOrder>
     * @Description 查询所有的景点订单
     */
    @Override
    public List<SightOrder> findAll() throws SightOrderException {
        try {
            return sightOrderDao.selectAll();
        } catch (SQLException e) {
            e.printStackTrace();
            throw new SightOrderException("查询所有的景点订单失败...");
        }
    }

    /**
     * @Description 通过用户id查询该用户的所有的景点订单
     *
     * @Param userId
     * @Return java.util.List<com.yoyo.itravel.bean.SightOrder>
     */
    @Override
    public List<SightOrder> findAllByUserId(String userId) throws SightOrderException {
        try {
            // 过用户id查询该用户的所有的景点订单
            List<SightOrder> sightOrders = sightOrderDao.selectByUserId(userId);
            /** 补充信息 **/
            // 遍历所有的订单
            for (SightOrder sightOrder : sightOrders) {
                // 获得具体门票类型对象
                TicketTypeDetail ticketTypeDetail = ticketTypeDetailDao.selectByTicketDetailTypeId(sightOrder.getDetailTypeId());
                // 将具体门票类型对象设置到订单对象中
                sightOrder.setTicketTypeDetail(ticketTypeDetail);
            }

            return sightOrders;
        } catch (SQLException e) {
            e.printStackTrace();
            throw new SightOrderException("通过用户id查询该用户的所有的景点订单失败...");
        }
    }

    /**
     * @Description 通过用户id和订单状态查询该用户待付款的景点订单
     *
     * @Param userId
     * @Param orderStatus
     * @Return java.util.List<com.yoyo.itravel.bean.SightOrder>
     */
    @Override
    public List<SightOrder> findByUserIdAndStatus(String userId, Integer orderStatus) throws SightOrderException {
        if (StringUtils.isEmpty(userId)) {
            throw new SightOrderException("用户id为空...");
        }

        try {
            // 过用户id查询该用户的所有的景点订单
            List<SightOrder> sightOrders = sightOrderDao.selectByUserIdAndStatus(userId, orderStatus);
            /** 补充信息 **/
            // 遍历所有的订单
            for (SightOrder sightOrder : sightOrders) {
                // 获得具体门票类型对象
                TicketTypeDetail ticketTypeDetail = ticketTypeDetailDao.selectByTicketDetailTypeId(sightOrder.getDetailTypeId());
                // 将具体门票类型对象设置到订单对象中
                sightOrder.setTicketTypeDetail(ticketTypeDetail);
            }

            return sightOrders;
        } catch (SQLException e) {
            e.printStackTrace();
            throw new SightOrderException("通过用户id和订单状态查询该用户待付款的景点订单失败...");
        }

    }

    /**
     * @param orderId
     * @return boolean
     * @Description 通过订单id删除订单
     */
    @Override
    public boolean deleteOrderByOrderId(String orderId) throws SightOrderException {
        if (StringUtils.isEmpty(orderId)) {
            throw new SightOrderException("订单号为空！");
        }
        try {
            return sightOrderDao.delete(orderId) == 1;
        } catch (SQLException e) {
            e.printStackTrace();
            throw new SightOrderException("通过订单id删除订单失败...");
        }
    }

    /**
     * @param orderId
     * @return cn.hut.travel.bean.SightOrder
     * @Description 通过订单id获得订单对象
     */
    @Override
    public SightOrder findByOrderId(String orderId) throws SightOrderException {
        if (StringUtils.isEmpty(orderId)) {
            throw new SightOrderException("订单号为空！");
        }
        try {
            SightOrder sightOrder = sightOrderDao.selectByOrderId(orderId);
            /** 补充信息 **/
            // 获得具体门票类型对象
            TicketTypeDetail ticketTypeDetail = ticketTypeDetailDao.selectByTicketDetailTypeId(sightOrder.getDetailTypeId());
            // 将具体门票类型对象设置到订单对象中
            sightOrder.setTicketTypeDetail(ticketTypeDetail);

            return sightOrder;
        } catch (SQLException e) {
            e.printStackTrace();
            throw new SightOrderException("通过订单id获得订单对象失败...");
        }
    }

    /**
     * @param orderId 订单号
     * @Description 订单未支付超时自动取消(设置指定时间未支付 ， 修改订单状态为已取消)
     */
    private void orderTimeoutCancel(final String orderId, final String sightTickeStockId, final Integer num) {
        final Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                try {
                    SightOrder sightOrder = sightOrderDao.selectByOrderId(orderId);
                    // 判断用户是否支付
                    if (sightOrder.getOrderStatus() == 1) { // 未支付
                        // 修改订单状态为已取消
                        updateOrderStatus(orderId, 0);
                        // 修改对应的库存数--库存数回滚
                        sightTicketStockDao.updateById(new SightTicketStock(sightTickeStockId, num));
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                // 中断线程
                timer.cancel();
            }
        }, OrderConstant.TIME_OUT);
    }

    /**
     * @param sightOrder 景点订单对象
     * @Description 订单支付后达到出行日期指定时间， 修改订单状态为带点评
     */
    private void orderCommentStatus(final SightOrder sightOrder) {
        final Timer timer = new Timer();
        Calendar c = Calendar.getInstance();
        c.setTime(sightOrder.getTripDate());
        c.add(Calendar.HOUR, OrderConstant.PRE_COMMENT_TIME);
        Date date = new Date(c.getTimeInMillis());

        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                try {
                    // 判断用户是否支付
                    if (sightOrder.getOrderStatus() == 2) { // 已支付
                        // 修改订单状态为待点评
                        updateOrderStatus(sightOrder.getOrderId(), 3);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                // 中断线程
                timer.cancel();
            }

        }, date);
    }

}
